﻿//  -------------------- iSharePoint -------------------- //
// 
//  Company:	IT Complex, LLC
//  Project:	Smart.Common
//  File name:	MetaWebScope.cs
//  Developer:	Solomatov Igor
//  Created:	15.04.2012
// 
//  -------------------- iSharePoint -------------------- //

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.SharePoint;

namespace Smart.Common
{
	/// <summary>
	/// Store metadata about Web
	/// </summary>
	[DebuggerDisplay("MetaWebScope Name={Name} Title={Title}")]
	public class MetaWebScope : MetaScope
	{
		/// <summary>
		/// Sub Web id
		/// </summary>
		public Dictionary<string, Guid> SubWebIDs { get; set; }

		/// <summary>
		/// Sub Webs collection
		/// </summary>
		public Dictionary<Guid, MetaWebScope> SubWebs { get; set; }

		/// <summary>
		/// Content types id
		/// </summary>
		public Dictionary<string, string> ContentTypeIDs { get; set; }

		/// <summary>
		/// Content types collection
		/// </summary>
		public Dictionary<string, MetaWebContentType> ContentTypes { get; set; }

		/// <summary>
		/// Web Url (full url)
		/// </summary>
		public string Url { get; set; }

		/// <summary>
		/// Web Url (server relative url)
		/// </summary>
		public string ServerRelativeUrl { get; set; }

		public MetaWebScope(SPWeb web)
			: base(web.ID, web.Name, web.Title)
		{
			Url = web.Url;
			ServerRelativeUrl = web.ServerRelativeUrl;

			SubWebIDs = new Dictionary<string, Guid>(StringComparer.OrdinalIgnoreCase);
			SubWebs = new Dictionary<Guid, MetaWebScope>();

			ContentTypeIDs = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
			ContentTypes = new Dictionary<string, MetaWebContentType>(StringComparer.OrdinalIgnoreCase);
		}

		/// <summary>
		/// Fill cache info
		/// </summary>
		public override void LoadLists(object source, ICollection<string> includeLists, IDictionary<string, FacadeMappingInfo> mappingInfo)
		{
			var web = (SPWeb)source;

			foreach (var list in web.Lists.OfType<SPList>().Where(list => !list.IsSystem()))
			{
				var url = list.ID.ToString();

				try
				{
					url = list.RootFolder.ServerRelativeUrl;

					var ml = new MetaWebList(list, this);

					if (includeLists == null ||
						includeLists.Contains(ml.Url) ||
						includeLists.Contains(ml.Name) ||
						includeLists.Contains(ml.Title) ||
						includeLists.Contains(ml.ID.ToString("D")) ||
						includeLists.Contains(ml.ID.ToString("B")))
					{
						ml.LoadFields(list);
						ml.LoadContentTypes(list);

						ListIDs[ml.Url] = ml.ID;
						ListIDs[ml.Name] = ml.ID;
						ListIDs[ml.Title] = ml.ID;
						ListIDs[ml.ID.ToString("D")] = ml.ID;
						ListIDs[ml.ID.ToString("B")] = ml.ID;

						Lists[ml.ID] = ml;
					}
				}
				catch (Exception x)
				{
					H.LX("MetaWebScope.LoadLists", "LoadLists Name: " + Name + ", url: " + url, x);
				}
			}
		}

		/// <summary>
		/// Load cache info
		/// </summary>
		public virtual void LoadSubWebs(SPWeb web)
		{
			var subWebs = web.Webs;

			for (int i = 0, iCnt = subWebs.Count; i < iCnt; i++)
			{
				using (var subWeb = subWebs[i])
				{
					try
					{
						var mw = new MetaWebScope(subWeb);

						mw.LoadLists(subWeb, null, null);
						mw.LoadContentTypes(subWeb);
						mw.LoadSubWebs(subWeb);

						SubWebIDs[mw.Url] = mw.ID;
						SubWebIDs[web.ServerRelativeUrl] = mw.ID;
						SubWebIDs[mw.Name] = mw.ID;
						SubWebIDs[mw.Title] = mw.ID;
						SubWebIDs[mw.ID.ToString("D")] = mw.ID;
						SubWebIDs[mw.ID.ToString("B")] = mw.ID;

						SubWebs[mw.ID] = mw;

						MetaCtx.SetWeb(subWeb, mw);
					}
					catch (Exception x)
					{
						H.LX("MetaWebScope.LoadSubWebs", x);
					}
				}
			}
		}

		/// <summary>
		/// Load content types
		/// </summary>
		public virtual void LoadContentTypes(SPWeb web)
		{
			if (web.ContentTypes == null)
				return;

			foreach (SPContentType ct in web.ContentTypes)
			{
				try
				{
					var mct =
						new MetaWebContentType(ct.Id.ToString(), ct.Parent.Id.ToString(), ct.Name, this)
								{
									DispFormUrl = ct.DisplayFormUrl,
									NewFormUrl = ct.NewFormUrl,
									EditFormUrl = ct.EditFormUrl
								};

					mct.LoadFields(ct);

					ContentTypeIDs[mct.Name] = mct.ID;
					ContentTypeIDs[mct.ID] = mct.ID;

					if (!ContentTypeIDs.ContainsKey(mct.ParentID))
						ContentTypeIDs[mct.ParentID] = mct.ID;

					ContentTypes[mct.ID] = mct;
				}
				catch (Exception x)
				{
					H.LX("MetaWebScope.LoadContentTypes", "LoadContentTypes ct.Id: " + ct.Id, x);
				}
			}
		}

		/// <summary>
		/// Return SPList from Web
		/// </summary>
		public virtual SPList List(SPWeb web, string titleOrUrl)
		{
			var id = ListIDs.SafeGet(titleOrUrl);

			var res = web.GetListById(id);

			if (res == null)
			{
				H.LT("MetaWebScope:List.Exception: list '{0}' not found at '{1}'!", titleOrUrl, Title);
			}

			return res;
		}

		/// <summary>
		/// Return SPList from Web
		/// </summary>
		public virtual SPList List(SPWeb web, Guid listId)
		{
			var res = web.GetListById(listId);

			if (res == null)
			{
				H.LT("MetaWebScope:List.1 Exception: list '{0}' not found at '{1}'!", listId, Title);
			}

			return res;
		}

		/// <summary>
		/// Return list Url by ListTitleOrUrl
		/// </summary>
		public virtual string ListUrl(string listTitleOrUrl)
		{
			var ml = (MetaWebList)List(listTitleOrUrl);

			return ml == null ? "_ERROR_LIST_NOT_FOUND_" : ml.Url;
		}

		/// <summary>
		/// Return list Url by Id
		/// </summary>
		public virtual string ListUrl(Guid id)
		{
			var ml = (MetaWebList)List(id);

			return ml == null ? "_ERROR_LIST_NOT_FOUND_" : ml.Url;
		}

		/// <summary>
		/// Return SubWeb by web id, name or url
		/// </summary>
		public virtual MetaWebScope SubWeb(string webId)
		{
			var id = SubWebIDs.SafeGet(webId);

			return
				id.IsEmpty()
					? null
					: SubWebs.SafeGet(id);
		}

		/// <summary>
		/// Return all SubWeb by web id, name or url
		/// </summary>
		public virtual MetaWebScope AllSubWeb(string webId)
		{
			var id = SubWebIDs.SafeGet(webId);

			var res =
				id.IsEmpty()
					? null
					: SubWebs.SafeGet(id);

			if (res != null)
				return res;

			foreach (var subWeb in SubWebs)
			{
				res = subWeb.Value.AllSubWeb(webId);

				if (res != null)
					return res;
			}

			return null;
		}

		/// <summary>
		/// Return MetaWebContentType by content type id or name
		/// </summary>
		public virtual MetaWebContentType ContentType(string contentType)
		{
			var id = ContentTypeIDs.SafeGet(contentType);

			if (id.IsNullOrEmpty())
				return null;

			return ContentTypes.SafeGet(id);
		}

		/// <summary>
		/// Checks whether list contains child or equal content types to <paramref name="contentTypeId"/>
		/// </summary>
		public virtual bool ContainsContentType(string contentTypeId)
		{
			foreach (var contentType in ContentTypes.Values)
			{
				if (contentType.ID.IsChildContentTypeOf(contentTypeId))
					return true;
			}

			return false;
		}

		/// <summary>
		/// Return all MetaWebContentTypes by content type id
		/// </summary>
		public virtual List<MetaWebContentType> AllContentTypes(string contentTypeId)
		{
			var res = new List<MetaWebContentType>();

			foreach (var contentType in ContentTypes.Values)
			{
				if (contentType.ID.IsChildContentTypeOf(contentTypeId))
					res.Add(contentType);
			}

			return res;
		}

		/// <summary>
		/// Find first occurance of list
		/// </summary>
		public virtual MetaList FindList(string listTitleOrUrl)
		{
			var ml = List(listTitleOrUrl);

			if (ml != null)
				return ml;

			foreach (var subWeb in SubWebs)
			{
				ml = subWeb.Value.FindList(listTitleOrUrl);

				if (ml != null)
					return ml;
			}

			return null;
		}
	}
}